#pragma once
// #include "reactor.hpp"
#include "util.hpp"
#include "cstring"
#include "unistd.h"
#include "sys/socket.h"
#include "eventItem.hpp"
#include "util.hpp"
struct data
{
    int _x;
    int _y;
    char _op; // "+-*/%" _x _oper _y
}; // --- "字符串"
int accepter(EventItem* item)
{
	while (true){
		struct sockaddr_in peer;
		memset(&peer, 0, sizeof(peer));
		socklen_t len = sizeof(peer);
		int sock = accept(item->_sock, (struct sockaddr*)&peer, &len);
		if (sock < 0){
			if (errno == EAGAIN || errno == EWOULDBLOCK){ //并没有读取出错，只是底层没有连接了
				return 0;
			}
			else if (errno == EINTR){ //读取的过程被信号中断了
				continue;
			}
			else{ //获取连接失败
				std::cerr << "accept error" << std::endl;
				return -1;
			}
		}
		SetNonBlock(sock); //将该套接字设置为非阻塞
		//构建EventItem结构
		EventItem sock_item;
		sock_item._sock = sock;
		sock_item._R = item->_R;
		sock_item.ManageCallbacks(recver, sender, errorer); //注册回调方法
		
		Reactor* R = item->_R;
		R->AddEvent(sock, EPOLLIN | EPOLLET, sock_item); //将该套接字及其对应的事件注册到Dispatcher中
	}
	return 0;
}
int recver_helper(int sock, std::string* out)
{
	while (true){
		char buffer[128];
		ssize_t size = recv(sock, buffer, sizeof(buffer)-1, 0);
		if (size < 0){
			if (errno == EAGAIN || errno == EWOULDBLOCK){ //数据读取完毕
				return 0;
			}
			else if (errno == EINTR){ //被信号中断，继续尝试读取
				continue;
			}
			else{ //读取出错
				return -1;
			}
		}
		else if (size == 0){ //对端连接关闭
			return -1;
		}
		//读取成功
		buffer[size] = '\0';
		*out += buffer; //将读取到的数据添加到该套接字对应EventItem结构的inbuffer中
	}
}

int recver(EventItem* item)
{
	if (item->_sock < 0) //该文件描述符已经被关闭
		return -1;
	//1、数据读取
	if (recver_helper(item->_sock, &(item->_inbuffer)) < 0){ //读取失败
		item->_error_handler(item);
		return -1;
	}

	//2、报文切割
	std::vector<std::string> datagrams;
	StringUtil::Split(item->_inbuffer, &datagrams, "X");

	for (auto s : datagrams){
		//3、反序列化
		struct data d;
		StringUtil::Deserialize(s, &d._x, &d._y, &d._op);

		//4、业务处理
		int result = 0;
		switch (d._op)
		{
			case '+':
				result = d._x + d._y;
				break;
			case '-':
				result = d._x - d._y;
				break;
			case '*':
				result = d._x * d._y;
				break;
			case '/':
				if (d._y == 0){
					std::cerr << "Error: div zero!" << std::endl;
					continue; //继续处理下一个报文
				}
				else{
					result = d._x / d._y;
				}
				break;
			case '%':
				if (d._y == 0){
					std::cerr << "Error: mod zero!" << std::endl;
					continue; //继续处理下一个报文
				}
				else{
					result = d._x % d._y;
				}
				break;
			default:
				std::cerr << "operation error!" << std::endl;
				continue; //继续处理下一个报文
		}

		//5、形成响应报文
		std::string response;
		response += std::to_string(d._x);
		response += d._op;
		response += std::to_string(d._y);
		response += "=";
		response += std::to_string(result);
		response += "X"; //报文与报文之间的分隔符
		
		//6、将响应报文添加到outbuffer中
		item->_outbuffer += response;
		if (!item->_outbuffer.empty())
			item->_R->EnableReadWrite(item->_sock, true, true); //打开写事件
	}
	return 0;
}
int sender_helper(int sock, std::string& in)
{
	size_t total = 0; //累加已经发送的字节数
	while (true){
		ssize_t size = send(sock, in.c_str() + total, in.size() - total, 0);
		if (size < 0){
			if (errno == EAGAIN || errno == EWOULDBLOCK){ //底层发送缓冲区已经没有空间了
				in.erase(0, total); //将已经发送的数据移出outbuffer
				return 1; //缓冲区写满，没写完
			}
			else if (errno == EINTR){ //被信号中断，继续尝试写入
				continue;
			}
			else{ //写入出错
				return -1;
			}
		}
		total += size;
		if (total >= in.size()){
			in.clear(); //清空outbuffer
			return 0; //全部写入完毕
		}
	}
}

int sender(EventItem* item)
{
	if (item->_sock < 0) //该文件描述符已经被关闭
		return -1;

	int ret = sender_helper(item->_sock, item->_outbuffer);
	if (ret == 0){ //全部发送成功，不再关心写事件
		item->_R->EnableReadWrite(item->_sock, true, false);
	}
	else if (ret == 1){ //没有发送完毕，还需要继续关心写事件
		item->_R->EnableReadWrite(item->_sock, true, true);
	}
	else{ //写入出错
		item->_error_handler(item);
	}
	return 0;
}
int errorer(EventItem* item)
{
	item->_R->DelEvent(item->_sock); //将该文件描述符从epoll模型中删除，并取消该文件描述符与其EventItem结构的映射关系
	close(item->_sock); //关闭该文件描述符

	item->_sock = -1; //防止关闭后继续执行读写回调
	return 0;
}
